from GeneticAlgorithm import *
import queue

InitialNumber = 20
deciding_time = 20
offloading_time = 20


# def Decide(network: Network, satellite_idx, block_idx):
#     row_idx, col_idx = network.Inv_CoordinationMapping(satellite_idx)
#     zgroup = Group(40, 4, network, 20, 10000, 1, row_idx, col_idx, block_idx)
#     zgroup.Iterate(10, 100, 40)
#     return zgroup.IndividualList[0].chromosome


class Event:
    def __init__(self, network: Network, row_idx, col_idx, block_idx, chromosome_idx, event_type, timestamp,
                 Decision_Function, *args):
        self.TimeStamp = timestamp
        self.Net = network
        self.EventType = event_type
        self.row_idx = row_idx
        self.col_idx = col_idx
        self.ChromosomeIndex = chromosome_idx
        self.BlockIndex = block_idx
        self.Decision_Individual = None
        self.Decision_Function = Decision_Function
        self.Decision_Arg = args

    def __lt__(self, other):
        return self.TimeStamp < other.TimeStamp

    def Execute(self):
        if self.EventType == -1:
            self.Decision_Individual = self.Decision_Function(self.Net, self.row_idx, self.col_idx, self.BlockIndex,
                                                              *self.Decision_Arg)
            self.Decision_Individual.AbandonSet.clear()
            self.TimeStamp += deciding_time
            self.ChromosomeIndex += 1
            self.EventType = 1
            return 0
        elif self.EventType == 1:
            # print(self.ChromosomeIndex, self.Decision_Individual.AbandonSet)
            real_processed_time, drop = self.Decision_Individual.ImplementSingle(self.ChromosomeIndex)
            self.TimeStamp += real_processed_time
            self.EventType = 0
            return drop
            # print(self.ChromosomeIndex, self.Decision_Individual.AbandonSet)
            # print("-" * 30)
        elif self.EventType == 0:
            self.TimeStamp += self.Decision_Individual.TT[self.ChromosomeIndex]
            self.Decision_Individual.OffloadSingle(self.ChromosomeIndex)
            if self.ChromosomeIndex == self.Decision_Individual.length - 1:
                self.EventType = 2
            else:
                self.EventType = 1
            self.ChromosomeIndex += 1
            return 0


class EventLine:
    def __init__(self, network: Network, Decision_Function, MaxSummonTime, *args):
        self.EventHeap = queue.PriorityQueue()
        self.Net = network
        self.MaximumUsage = 0
        self.TotalTime = 0
        self.TheoreticalTime = sum(
            [sum([sum([task.WorkLoadSum for task in satellite.TaskList]) for satellite in orbit]) for orbit in
             self.Net.SatelliteGroup])
        self.TotalMission = sum(
            [sum([satellite.TaskNumber for satellite in orbit]) for orbit in self.Net.SatelliteGroup])
        self.TotalDrop = 0
        for i in range(self.Net.TotalSatelliteNumber):
            row_idx, col_idx = self.Net.Inv_CoordinationMapping(i)
            for j in range(len(self.Net.Get(i).TaskBlock)):
                random_timestamp = random.uniform(0, MaxSummonTime)
                self.EventHeap.put(Event(network, row_idx, col_idx, j, -1, -1, random_timestamp,
                                         Decision_Function,
                                         *args))

    def Simulate(self):
        self.MaximumUsage = 0
        while self.EventHeap.qsize() > 0:
            event = self.EventHeap.get()
            # print(kind, event.TimeStamp)
            # if kind == 1:
            #     print(event.ChromosomeIndex, event.Decision_Individual.chromosome)
            #     for orbit in self.Net.SatelliteGroup:
            #         for s in orbit:
            #             print('{0: <5}'.format(round(1 - s.ResidualResource(), 3)), end=" ")
            #         print(" ")
            if event.EventType != 2:
                # IncreasedDrop = event.Execute()
                self.TotalDrop += event.Execute()
                self.EventHeap.put(event)
                self.MaximumUsage = max(self.MaximumUsage, 1 - self.Net.GetResource())
            self.TotalTime = max([self.TotalTime, event.TimeStamp])
            # print(self.TotalTime)

# X = [i for i in range(1, 21)]
# GA1_rate = [0 for _ in range(1, 21)]
# GA2_rate = [0 for _ in range(1, 21)]
# GA3_rate = [0 for _ in range(1, 21)]
# for j in range(3):
#     for i in range(1, 20):
#         network = Network(8, 8,
#                           1, 4,
#                           8, 2 * i,
#                           2, 20,
#                           1, 400,
#                           1000, 3)
#         GA2 = EventLine(network, GA_Decision, 20000, 20, 3, 20, pow(10, 9), 1, 10, 100, 10, 10)
#         GA1 = EventLine(network, GA_Decision, 20000, 40, 3, 20, pow(10, 9), 1, 20, 100, 20, 20)
#         GA3 = EventLine(network, GA_Decision, 20000, 10, 3, 20, pow(10, 9), 1, 20, 100, 5, 25)
#         GA1.Simulate()
#         GA2.Simulate()
#         GA3.Simulate()
#         GA1_rate[i] += GA1.TotalDrop / GA1.TotalMission
#         GA2_rate[i] += GA2.TotalDrop / GA2.TotalMission
#         GA3_rate[i] += GA3.TotalDrop / GA3.TotalMission
#         print("Finished:", j, i)
#
# GA1_rate = [ele / 3 for ele in GA1_rate]
# GA2_rate = [ele / 3 for ele in GA2_rate]
# GA3_rate = [ele / 3 for ele in GA3_rate]
# plt.plot(X, GA1_rate, 'b*--')
# plt.plot(X, GA2_rate, 'r*--')
# plt.plot(X, GA3_rate, 'y*--')
# plt.legend(['GA1', 'GA2', 'GA3'], loc='upper left')
# plt.show()
